#线程代码的封装
import threading
from threading import Thread
import time
'''
class Exp(Thread):
    def run(self):
        print(f'重构run方法，开始子线程,对象名称为{self.name}')
        print(f'当前线程为{threading.current_thread().name}')
        time1=time.time()
        time.sleep(2)
        time2=time.time()
        print('结束了子线程{},共计用时{}秒'.format(threading.current_thread().name,time2-time1))
if __name__=='__main__':
    t1=Exp()
    t2=Exp()
    t1.start()#用start调用run函数
    t2.start()

重构run方法，开始子线程,对象名称为Thread-1
当前线程为Thread-1
重构run方法，开始子线程,对象名称为Thread-2
当前线程为Thread-2
结束了子线程Thread-1,共计用时2.000058889389038秒
结束了子线程Thread-2,共计用时2.000596284866333秒

'''
#有了threading.current_thread().name，就可以验证线程的调度是无序的
def exp():
    time.sleep(1)
    print(f'当前线程为:{threading.current_thread().name}\n',end='')
'''
if __name__=='__main__':
    for i in range(5):
        exp()
'''
'''
当前线程为:MainThread
当前线程为:MainThread
当前线程为:MainThread
当前线程为:MainThread
当前线程为:MainThread
''''''
if __name__=='__main__':
    for i in range(5):
        t=threading.Thread(target=exp)
        t.start()
''''''
当前线程为:Thread-1 (exp)
当前线程为:Thread-2 (exp)
当前线程为:Thread-3 (exp)
当前线程为:Thread-4 (exp)
当前线程为:Thread-5 (exp)
''''''
if __name__=='__main__':
    t=threading.Thread(target=exp)
    try:
        for i in range(5):
            t.start()
    except RuntimeError as e:
        print('警告：{}'.format(e))#警告：threads can only be started once
#raise RuntimeError("threads can only be started once")
''''''
#阻塞线程的应用
list1=[]
def write_in():
    for i in range(5):
        list1.append(i)
        time.sleep(0.2)
        print(f'添加的后的结果为：{list1}\n',end='')
test=threading.Thread(target=write_in)
test.start()

#print(f'现在list1中的数据为：{list1}')
''''''
现在list1中的数据为：[0]
添加的后的结果为：[0]
添加的后的结果为：[0, 1]
添加的后的结果为：[0, 1, 2]
添加的后的结果为：[0, 1, 2, 3]
添加的后的结果为：[0, 1, 2, 3, 4]
怎么绘世呢？是因为子线程sleep的时候先把主线程执行完了
这好吗，这不好，所以需要使用join阻塞主线程
''''''
test.join()
print(f'现在list1中的数据为：{list1}')
''''''
添加的后的结果为：[0]
添加的后的结果为：[0, 1]
添加的后的结果为：[0, 1, 2]
添加的后的结果为：[0, 1, 2, 3]
添加的后的结果为：[0, 1, 2, 3, 4]
现在list1中的数据为：[0, 1, 2, 3, 4]
这样就使得主线程在子线程结束后再执行
'''
#线程竞争：
exp1=0
exp2=1000000
def add1():
    global exp1
    for i in range(exp2):
        exp1+=1
    print(f'这是函数add1,exp1结果为{exp1}\n',end='')
'''
t1=threading.Thread(target=add1)
t2=threading.Thread(target=add1)
t1.start()
t2.start()
'''
'''
第一次执行：
这是函数add1,exp1结果为1723121
这是函数add1,exp1结果为2000000
第二次执行：
这是函数add1,exp1结果为1319932
这是函数add1,exp1结果为2000000
因此得出结论：两个进程同时进行的时候，会对相同的资源产生竞争，而且由于资源调度的问题，每一次的结果都不相同
想要避免资源的竞争：
1）join阻塞进程，让进程按顺序执行
2）互斥锁：让多个线程访问数据时不会产生错误的问题（对共享的数据进行锁定，先抢到的进程先执行，一次只执行一个线程）
'''
lock = threading.Lock()
def add2():
    lock.acquire()
    global exp1
    for i in range(exp2):
        exp1 += 1
    print(f'这是函数add2,exp1结果为{exp1}\n', end='')
    lock.release()
'''
t1=threading.Thread(target=add2)
t2=threading.Thread(target=add2)
t1.start()
t2.start()
'''
'''
这是函数add2,exp1结果为1000000
这是函数add2,exp1结果为2000000
'''
#或者：
t3=threading.Thread(target=add1)
t4=threading.Thread(target=add1)
t3.start()
t3.join()
t4.start()
'''
这是函数add1,exp1结果为1000000
这是函数add1,exp1结果为2000000
'''
